#property copyright "Copyright 2011, Eric"
#property link      "mingxinhe@gmail.com"

#property indicator_chart_window

#define NONOE -1
#define BULLISH_ENGULFING 1
#define BEARISH_ENGULFING 2
#define HARAMI 3
#define HAMMER 4
#define SHOOTING_STAR 5
#define BULLISH_DARKCLOUD 6
#define BEARISH_DARKCLOUD 7
//----
extern string CurrencyList = "EURUSD,GBPUSD,USDCHF,USDCAD,USDJPY,AUDUSD,NZDUSD";
extern bool M5_Enable = true;
extern bool M15_Enable = true;
extern bool M30_Enable = true;
extern bool H1_Enable = true;
extern bool H4_Enable = true;
extern bool D1_Enable = true;
extern bool W1_Enable = true;

extern bool Contra_Dir_Filter = true;
extern bool ShootingStar_Hammer_Filter = true;
extern bool Harami_Filter = true;
extern int  Consecutive_candels = 3;
extern bool Text.Alert = true;
extern bool Sound.Alert = true;
extern bool Email.Alert = true;
extern string SoundFileName = "Alert.wav";

#define NUM_TF 7

int U=20,L=0;
int barCount[][NUM_TF];
string symbols[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{       
    SplitString(CurrencyList, ",", symbols);
    ArrayResize(barCount, ArraySize(symbols));
       
    int SY,I,Y=31+U,X=23+L,Y2=Y-19,X2=X+72,X3=X2+2,Y3=Y;SY=Y3;
    string tex=""; 
    for(int i=0;i<ArraySize(symbols);i++)
    {
         tex=""; tex=symbols[i];   
         ObjectCreate(tex+"EricHe",23,0,0,0);
         ObjectSet(tex+"EricHe",102,X2);ObjectSet(tex+"EricHe",103,Y2);X2+=80;
         ObjectSetText(tex+"EricHe",tex,10,"Arial",Orange);
    }
    
    if (M5_Enable)
    {
         tex= "M5EricHe";
         ObjectCreate(tex,23,0,0,0);
         ObjectSet(tex,OBJPROP_XDISTANCE,X);ObjectSet(tex,OBJPROP_YDISTANCE,Y);Y+=50;
         ObjectSetText(tex,"M5",12,"Arial",DeepSkyBlue);
    }
    if (M15_Enable)
    {
         tex= "M15EricHe";
         ObjectCreate(tex,23,0,0,0);
         ObjectSet(tex,OBJPROP_XDISTANCE,X);ObjectSet(tex,OBJPROP_YDISTANCE,Y);Y+=50;
         ObjectSetText(tex,"M15",12,"Arial",DeepSkyBlue);
    }
    if (M30_Enable)
    {
         tex= "M30EricHe";
         ObjectCreate(tex,23,0,0,0);
         ObjectSet(tex,OBJPROP_XDISTANCE,X);ObjectSet(tex,OBJPROP_YDISTANCE,Y);Y+=50;
         ObjectSetText(tex,"M30",12,"Arial",DeepSkyBlue);
    }
    if (H1_Enable)
    {
         tex= "H1EricHe";
         ObjectCreate(tex,23,0,0,0);
         ObjectSet(tex,OBJPROP_XDISTANCE,X);ObjectSet(tex,OBJPROP_YDISTANCE,Y);Y+=50;
         ObjectSetText(tex,"H1",12,"Arial",DeepSkyBlue);
    }
    if (H4_Enable)
    {
         tex= "H4EricHe";
         ObjectCreate(tex,23,0,0,0);
         ObjectSet(tex,OBJPROP_XDISTANCE,X);ObjectSet(tex,OBJPROP_YDISTANCE,Y);Y+=50;
         ObjectSetText(tex,"H4",12,"Arial",DeepSkyBlue);
    }
    if (D1_Enable)
    {
         tex= "D1EricHe";
         ObjectCreate(tex,23,0,0,0);
         ObjectSet(tex,OBJPROP_XDISTANCE,X);ObjectSet(tex,OBJPROP_YDISTANCE,Y);Y+=50;
         ObjectSetText(tex,"D1",12,"Arial",DeepSkyBlue);
    }
    if (W1_Enable)
    {
         tex= "W1EricHe";
         ObjectCreate(tex,23,0,0,0);
         ObjectSet(tex,OBJPROP_XDISTANCE,X);ObjectSet(tex,OBJPROP_YDISTANCE,Y);Y+=50;
         ObjectSetText(tex,"W1",12,"Arial",DeepSkyBlue);
    }
   
   for(i=0;i<ArraySize(symbols);i++)
   {
       if (M5_Enable)
       {
           tex=symbols[i]+"_M5";
           ObjectCreate(tex,23,0,0,0);
           ObjectSet(tex,102,X3);ObjectSet(tex,103,Y3);Y3+=50;
           ObjectSetText(tex,"",12,"Times New Roman",DarkViolet);
       }
       if (M15_Enable)
       {
           tex=symbols[i]+"_M15";
           ObjectCreate(tex,23,0,0,0);
           ObjectSet(tex,102,X3);ObjectSet(tex,103,Y3);Y3+=50;
           ObjectSetText(tex,"",12,"Times New Roman",DarkViolet);
       }
       if (M30_Enable)
       {
           tex=symbols[i]+"_M30";
           ObjectCreate(tex,23,0,0,0);
           ObjectSet(tex,102,X3);ObjectSet(tex,103,Y3);Y3+=50;
           ObjectSetText(tex,"",12,"Times New Roman",DarkViolet);
       }
       if (H1_Enable)
       {
           tex=symbols[i]+"_H1";
           ObjectCreate(tex,23,0,0,0);
           ObjectSet(tex,102,X3);ObjectSet(tex,103,Y3);Y3+=50;
           ObjectSetText(tex,"",12,"Times New Roman",DarkViolet);
       }
       if (H4_Enable)
       {
           tex=symbols[i]+"_H4";
           ObjectCreate(tex,23,0,0,0);
           ObjectSet(tex,102,X3);ObjectSet(tex,103,Y3);Y3+=50;
           ObjectSetText(tex,"",12,"Times New Roman",DarkViolet);
       }
       if (D1_Enable)
       {
           tex=symbols[i]+"_D1";
           ObjectCreate(tex,23,0,0,0);
           ObjectSet(tex,102,X3);ObjectSet(tex,103,Y3);Y3+=50;
           ObjectSetText(tex,"",12,"Times New Roman",DarkViolet);
       }
       if (W1_Enable)
       {
           tex=symbols[i]+"_W1";
           ObjectCreate(tex,23,0,0,0);
           ObjectSet(tex,102,X3);ObjectSet(tex,103,Y3);Y3+=50;
           ObjectSetText(tex,"",12,"Times New Roman",DarkViolet);
       }
       //Y3+=40;X3=SX+2;
       X3+=80;Y3=SY;
   }

}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
{
    ObjectsDeleteAll();
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{
    for(int i=0;i<ArraySize(symbols);i++)
    {   
        int Pattern = -1;
        if (M5_Enable && barCount[i][0]!=iBars(symbols[i],PERIOD_M5))
        {
            Pattern = getPattern(1, symbols[i], PERIOD_M5);
            Print(symbols[i]," M5:", Pattern);
            int timeFrame = PERIOD_M5;
            barCount[i][0] = iBars(symbols[i],PERIOD_M5);
            doAlert(symbols[i], timeFrame, Pattern);            
            ObjectSetText(symbols[i]+"_M5",getAbrPatternName(Pattern),12,"Times New Roman",Red);
        }
        if (M15_Enable && barCount[i][1]!=iBars(symbols[i],PERIOD_M15))
        {
            Pattern = getPattern(1, symbols[i], PERIOD_M15);
            Print("M15:", Pattern);
            timeFrame = PERIOD_M15;
            barCount[i][1]=iBars(symbols[i],PERIOD_M15);
            doAlert(symbols[i], timeFrame, Pattern);
            ObjectSetText(symbols[i]+"_M15",getAbrPatternName(Pattern),12,"Times New Roman",Red);
        }
        if (M30_Enable && barCount[i][2]!=iBars(symbols[i],PERIOD_M30))
        {
            Pattern = getPattern(1, symbols[i], PERIOD_M30);
            Print("M30:", Pattern);
            timeFrame = PERIOD_M30;
            barCount[i][2]=iBars(symbols[i],PERIOD_M30);
            doAlert(symbols[i], timeFrame, Pattern);
            ObjectSetText(symbols[i]+"_M30",getAbrPatternName(Pattern),12,"Times New Roman",Red);
        }
        if (H1_Enable && barCount[i][3]!=iBars(symbols[i],PERIOD_H1))
        {
            Pattern = getPattern(1, symbols[i], PERIOD_H1);
            Print("H1:", Pattern);
            timeFrame = PERIOD_H1;
            barCount[i][3]=iBars(symbols[i],PERIOD_H1);
            doAlert(symbols[i], timeFrame, Pattern);
            ObjectSetText(symbols[i]+"_H1",getAbrPatternName(Pattern),12,"Times New Roman",Red);
        }
        if (H4_Enable && barCount[i][4]!=iBars(symbols[i],PERIOD_H4))
        {
            Pattern = getPattern(1, symbols[i], PERIOD_H4);
            Print("H4:", Pattern);
            timeFrame = PERIOD_H4;
            barCount[i][4]=iBars(symbols[i],PERIOD_H4);
            doAlert(symbols[i], timeFrame, Pattern);
            ObjectSetText(symbols[i]+"_H4",getAbrPatternName(Pattern),12,"Times New Roman",Red);
        }
        if (D1_Enable && barCount[i][5]!=iBars(symbols[i],PERIOD_D1))
        {
            Pattern = getPattern(1, symbols[i], PERIOD_D1);
            Print("D1:", Pattern);
            timeFrame = PERIOD_D1;
            barCount[i][5]=iBars(symbols[i],PERIOD_D1);
            doAlert(symbols[i], timeFrame, Pattern);
            ObjectSetText(symbols[i]+"_D1",getAbrPatternName(Pattern),12,"Times New Roman",Red);
        }
        if (W1_Enable && barCount[i][6]!=iBars(symbols[i],PERIOD_W1))
        {
            Pattern = getPattern(1, symbols[i], PERIOD_W1);
            Print("W1:", Pattern);
            timeFrame = PERIOD_W1;
            barCount[i][6]=iBars(symbols[i],PERIOD_W1);
            doAlert(symbols[i], timeFrame, Pattern);
            ObjectSetText(symbols[i]+"_W1",getAbrPatternName(Pattern),12,"Times New Roman",Red);
        }   
    }  
}

void doAlert(string symbol, int timeFrame, int Pattern)
{
      if (Pattern < 0) return;
      string alertStr = "Pair:" + symbol + ", T/F:" +  getTimeFrame(timeFrame) + ", Pattern:" + getPatternName(Pattern);                   
      if (Text.Alert)
      {
          Alert(alertStr);
          Print(alertStr);
      }
      if (Email.Alert)
      {
          SendMail("Candle Pattern Alert" , alertStr);  
      }
      if (Sound.Alert)
      {
          PlaySound(SoundFileName);
      }   
}

string getPatternName(int Pattern)
{
   switch(Pattern)
   {
      case BEARISH_ENGULFING: return("Bearish Engulfing");
      case SHOOTING_STAR: return("Shooting Star");
      case BEARISH_DARKCLOUD: return("Bearish Dark cloud");
      case BULLISH_ENGULFING: return("Bullish Engulfing");
      case HARAMI: return("Harami");
      case HAMMER: return("Hammer");
      case BULLISH_DARKCLOUD: return("Bullish Dark cloud");
   }
}

string getAbrPatternName(int Pattern)
{
   switch(Pattern)
   {
      case BEARISH_ENGULFING: return("Been");
      case SHOOTING_STAR: return("Shst");
      case BEARISH_DARKCLOUD: return("Bedc");
      case BULLISH_ENGULFING: return("Buen");
      case HARAMI: return("Har");
      case HAMMER: return("Ham");
      case BULLISH_DARKCLOUD: return("Budc");
   }
   
   return (" ");
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string getTimeFrame(int tf)
{
switch(tf)
 {
 case 1: return("M1");
 case 5: return("M5");
 case 15: return("M15");
 case 30: return("M30");
 case 60: return("H1");
 case 240: return("H4");
 case 1440: return("D1");
 case 10080: return("W1");
 case 43200: return("MN");
 }
}

// *************************************************************************************
// Service function for splitting a string into an array of values. For example,
// it can be used to take a comma-separated line (read using ReadLineFromFile() etc)
// and break it into an array of its comma-delimited parts.
// Example usage is:
//      string Results[];
//      StringSplit("abc,def,ghi", ",", Results);
// *************************************************************************************
bool SplitString(string stringValue, string separatorSymbol, string& results[], int expectedResultCount = 0)
{
   if (StringFind(stringValue, separatorSymbol) < 0)
   {// No separators found, the entire string is the result.
      ArrayResize(results, 1);
      results[0] = stringValue;
   }
   else
   {   
      int separatorPos = 0;
      int newSeparatorPos = 0;
      int size = 0;

      while(newSeparatorPos > -1)
      {
         size = size + 1;
         newSeparatorPos = StringFind(stringValue, separatorSymbol, separatorPos);
         
         ArrayResize(results, size);
         if (newSeparatorPos > -1)
         {
            if (newSeparatorPos - separatorPos > 0)
            {  // Evade filling empty positions, since 0 size is considered by the StringSubstr as entire string to the end.
               results[size-1] = StringSubstr(stringValue, separatorPos, newSeparatorPos - separatorPos);               
            }
         }
         else
         {  // Reached final element.
            results[size-1] = StringSubstr(stringValue, separatorPos, 0);
         }         
         results[size-1] = StringTrimLeft(StringTrimRight(results[size-1]));
         
         separatorPos = newSeparatorPos + 1;
      }
   }   
   
   if (expectedResultCount == 0 || expectedResultCount == ArraySize(results))
   {  // Results OK.
      return (true);
   }
   else
   {  // Results are WRONG.
      Print("ERROR - size of parsed string not expected.");
      return (false);
   }
}

int getPattern(int shift1,string symbol,int timeframe)
{
    int shift2 = shift1 + 1;
    int shift3 = shift1 + 2;
    int shift4 = shift1 + 3;
      
    double O1 = iOpen(symbol, timeframe, shift1);
    double O2 = iOpen(symbol, timeframe, shift2);
    double H1 = iHigh(symbol, timeframe, shift1);
    double H2 = iHigh(symbol, timeframe, shift2);
    double H3 = iHigh(symbol, timeframe, shift3);
    double H4 = iHigh(symbol, timeframe, shift4);
    double L1 = iLow(symbol, timeframe, shift1);
    double L2 = iLow(symbol, timeframe, shift2);
    double L3 = iLow(symbol, timeframe, shift3);
    double L4 = iLow(symbol, timeframe, shift4);
    double C1 = iClose(symbol, timeframe, shift1);
    double C2 = iClose(symbol, timeframe, shift2);
               
    if (Contra_Dir_Filter)
    {
        int i = 1;
        for (; i <= Consecutive_candels; i++)
        {
            if (C1 >= O1)
            {
                if (iClose(symbol, timeframe, shift1 + i) >= iOpen(symbol, timeframe,shift1+i))
                {
                    break;            
                }
            }
            else if (C1 <= O1)
            {
                if (iClose(symbol, timeframe, shift1 + i) <= iOpen(symbol, timeframe,shift1+i))
                {
                    break;            
                }
            }
        }
        
        if (i <= Consecutive_candels)
        {
            return (NONOE);
        }
    }
   
    // Bearish Patterns
      // Check for Bearish Engulfing pattern
      if ( L1<L2 && H1 > H2 && C1 <= L1 + (H1-L1)/3.0) {
          return (BEARISH_ENGULFING);
      }
      
      // Check for Bearish Harami pattern
      
      if (!Harami_Filter
         || MathAbs(O1 - C1) > (H1 - L1)/2
      )
      {
         if (L1 > L2 && H1 < H2) {
             return (HARAMI);
         }
      }
      
      if (!ShootingStar_Hammer_Filter
          || (H1 - L1 > (H2 - L2 + H3 - L3 + H4 - L4) /3)
         )
      {      
         if (L1 < L2 && O1 >= H1 - (H1 - L1)/3.0 && C1 >= H1 - (H1 - L1)/3.0) {
             return (HAMMER);
         }
      
         if ( H1 > H2 && O1 <= L1 + (H1 - L1)/3.0 && C1 <= L1 + (H1 - L1)/3.0) {
             return (SHOOTING_STAR);   
         }
      }
      
      if ( L1 < L2 && C1 >= (H2+L2)*0.5 && C1 <= H2) {
          return (BULLISH_DARKCLOUD);   
      }
      
      if ( H1 > H2 && C1 <= (H2+L2)*0.5 && C1 >= L2) {
          return (BEARISH_DARKCLOUD);   
      }
      
      
   // End of Bearish Patterns
   
   // Bullish Patterns
   
      // Check for Bullish Engulfing pattern
      
      if ( L1 < L2 && H1 > H2 && C1 >= H1 -(H1 - L1)/3.0) {
         return (BULLISH_ENGULFING);
      }
      
      return (NONOE);
}
//----

